/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package fr.irit.etracetool.etrace.impl;

import java.util.Collection;

import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.util.EObjectContainmentEList;
import org.eclipse.emf.ecore.util.InternalEList;

import fr.irit.etracetool.etrace.AbstractLink;
import fr.irit.etracetool.etrace.CompositeLink;
import fr.irit.etracetool.etrace.EtraceFactory;
import fr.irit.etracetool.etrace.EtracePackage;
import fr.irit.etracetool.etrace.Link;
import fr.irit.etracetool.etrace.LinkType;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Composite Link</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link fr.irit.etracetool.etrace.impl.CompositeLinkImpl#getChildren <em>Children</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class CompositeLinkImpl extends AbstractLinkImpl implements CompositeLink {
	/**
	 * The cached value of the '{@link #getChildren() <em>Children</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getChildren()
	 * @generated
	 * @ordered
	 */
	protected EList<AbstractLink> children;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected CompositeLinkImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return EtracePackage.Literals.COMPOSITE_LINK;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<AbstractLink> getChildren() {
		if (children == null) {
			children = new EObjectContainmentEList<AbstractLink>(AbstractLink.class, this, EtracePackage.COMPOSITE_LINK__CHILDREN);
		}
		return children;
	}

	/**
	 * <!-- begin-user-doc -->
	 * Create a new link and add it in the children list.
	 * @return the new link 
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public Link createLink() {
		Link l = EtraceFactory.eINSTANCE.createLink();
		children.add(l);
		return l;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public Link createLink(EObject source, EObject target, LinkType type) {
		Link l = createLink();
		initializeLink(l, source, target, type);
		return l;
	}

	private void initializeLink(Link l, EObject source, EObject target,
			LinkType type) {
		l.setSource(source);
		l.setTarget(target);
		l.setType(type);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public CompositeLink createCompositeLink() {
		CompositeLink cl = EtraceFactory.eINSTANCE.createCompositeLink();
		return cl;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public EList<EObject> getAllSources() {
		EList<EObject> l = new BasicEList<EObject>();
		getSources(this, l);
		return l;
	}

	private void getSources(CompositeLink root,
			EList<EObject> list) {
		if (root.getSource() != null) {
			list.add(root.getSource());
		}
		for (AbstractLink child : root.getChildren()) {
			if (child instanceof Link && child.getSource() != null) {
				list.add(child.getSource());
			}
			if (child instanceof CompositeLink) {
				getSources((CompositeLink) child, list);
			}
		}
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public EList<EObject> getAllTargets() {
		EList<EObject> l = new BasicEList<EObject>();
		getTargets(this, l);
		return l;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public EList<EObject> getAllReferencedElements() {
		EList<EObject> l = new BasicEList<EObject>();
		l.addAll(getAllSources());
		l.addAll(getAllTargets());
		return l;
	}

	private void getTargets(CompositeLink root,
			EList<EObject> list) {
		if (root.getTarget() != null) {
			list.add(root.getTarget());
		}
		for (AbstractLink child : root.getChildren()) {
			if (child instanceof Link && child.getTarget() != null) {
				list.add(child.getTarget());
			}
			if (child instanceof CompositeLink) {
				getTargets((CompositeLink) child, list);
			}
		}
	}

	/**
	 * <!-- begin-user-doc -->
	 * Return all the Link include in the composite link, in a flat form.
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public EList<Link> getAllLinks() {
		BasicEList<Link> list = new BasicEList<Link>();
		return getAllLinksInternal(list, this);
	}
	
	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public EList<CompositeLink> getAllCompositeLinks() {
		BasicEList<CompositeLink> list = new BasicEList<CompositeLink>();
		return getAllCompositeLinksInternal(list, this);
	}

	private EList<CompositeLink> getAllCompositeLinksInternal(
			BasicEList<CompositeLink> list, CompositeLink cl) {
		list.add(cl);
		for (AbstractLink al: cl.getChildren()) {
			if (al instanceof CompositeLink) {
				getAllCompositeLinksInternal(list, (CompositeLink) al);
			}
		}
		return list;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public int numberOfLinks() {
		return getAllLinks().size();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public int numberOfCompositeLinks() {
		return getAllCompositeLinks().size();
	}

	private EList<Link> getAllLinksInternal(EList<Link> list, CompositeLink root) {
		for (AbstractLink al: root.getChildren()) {
			if (al instanceof Link) {
				list.add((Link)al);
			}
			else getAllLinksInternal(list, (CompositeLink) al);
		}
		return list;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
		switch (featureID) {
			case EtracePackage.COMPOSITE_LINK__CHILDREN:
				return ((InternalEList<?>)getChildren()).basicRemove(otherEnd, msgs);
		}
		return super.eInverseRemove(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case EtracePackage.COMPOSITE_LINK__CHILDREN:
				return getChildren();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case EtracePackage.COMPOSITE_LINK__CHILDREN:
				getChildren().clear();
				getChildren().addAll((Collection<? extends AbstractLink>)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case EtracePackage.COMPOSITE_LINK__CHILDREN:
				getChildren().clear();
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case EtracePackage.COMPOSITE_LINK__CHILDREN:
				return children != null && !children.isEmpty();
		}
		return super.eIsSet(featureID);
	}

} //CompositeLinkImpl
